#pragma once

#include <iostream>
#include <algorithm>
#include <memory>
#include <cstring>
#include <sys/select.h>
#include <poll.h>
#include "Socket.hpp"

using namespace SocketModule;
class pollservice
{
    const static int defaultCapacity = 1024; // 默认大小，poll默认可以容纳1024个fd
    const static int defaultFd = -1;
public:
    pollservice(uint16_t port)
        :_listensock(std::make_unique<TcpSocket>()),
         _isRunning(false),
         _fds_pos(0),
         _capacity(defaultCapacity)
    {
        _listensock->BuildTcpSocket(port); 

        // 动态申请空间来管理所有的fd，并将数据都置为-1
        _fds_array = static_cast<struct pollfd*>(malloc(_capacity * sizeof(struct pollfd)));
        if(!_fds_array) {
            std::cerr << "malloc error" << std::endl;
            abort();
        }
        memset(_fds_array, defaultFd, sizeof(struct pollfd) * _capacity);

        // 将listensockfd绑定到第一个位置
        _fds_array[_fds_pos].fd = _listensock->Fd();
        _fds_array[_fds_pos++].events = POLLIN;
    }

    ~pollservice()
    {
        for(int i = 0; i<_fds_pos; i++) {
            if(_fds_array[i].fd == defaultFd) continue;
            close(_fds_array[i].fd);
        }

        free(_fds_array);
    }

    void Strat()
    {
        _isRunning = true;
        while(_isRunning) {
            printFd();

            int n = poll(_fds_array, _fds_pos, -1);
            if(n > 0) {
                LOG(loglevel::INFO) << "event-ready... n:" << n;
                Dispath();
            }
            else if(n == 0) {
                LOG(loglevel::INFO) << "time out...";
            }
            else {
                std::cerr << "poll error" << std::endl;
                break;
            }
        }
        _isRunning = false;
    }

    // 事件派发器
    void Dispath()
    {
        for(int i=0; i<_fds_pos; i++) {
            if(_fds_array[i].fd == defaultFd) continue;
            if(_fds_array[i].revents & POLLIN) {
                // 读就绪
                if(_fds_array[i].fd == _listensock->Fd()) {
                    // listensockfd
                    Accepter();
                }
                else {
                    // sockfd
                    Recver(i);
                }
            }
        }
    }

    // 连接管理器
    void Accepter()
    {
        InetAddr client;
        int sockfd = _listensock->Accept(&client);

        // 将来这个连接也是需要IO的，所以交给poll去等待
        if(_fds_pos < _capacity) {
            _fds_array[_fds_pos].fd = sockfd;
            _fds_array[_fds_pos++].events = POLLIN;
        }
        else {
            // 此时_fds_array已经满了，需要动态扩容
            if(!Expansion()) {
                // 扩容失败
                LOG(loglevel::FATAL) << "_fds_array full, and expansion fail";
                free(_fds_array);
                abort();
            }
            LOG(loglevel::INFO) << "expansion success";
            _fds_array[_fds_pos].fd = sockfd;
            _fds_array[_fds_pos++].events = POLLIN;
        }
    }

    bool Expansion()
    {
        _capacity *= 2;
        void * newbuffer = realloc(_fds_array, _capacity * sizeof(struct pollfd));
        if(!newbuffer) {
            return false;
        }
        _fds_array = static_cast<struct pollfd*>(newbuffer);
        return true;
    }

    // IO处理器
    void Recver(int pos)
    {
        // 到了IO处理器，说明此时该fd的读事件是就绪的，现在直接recv/read不会阻塞
        // 但是直接读取还是有问题的，因为Tcp报文是面向字节流的，我们不知道是否能将一个报文读全
        char buffer[1024] = {0};
        while(true) {
            ssize_t n = recv(_fds_array[pos].fd, buffer, sizeof(buffer) - 1, 0); // 0表示阻塞读取，但这里绝对不会阻塞
            if(n > 0) {
                std::cout << "client say$ " << buffer << std::endl;
            }
            else if(n == 0) {
                // 客户端退出，将该连接关闭，同时从辅助数组中去除
                std::cout << "client quit" << std::endl;
                close(_fds_array[pos].fd);
                _fds_array[pos].fd = defaultFd;
                break;
            }
            else {
                std::cerr << "recv error" << std::endl;
                close(_fds_array[pos].fd);
                _fds_array[pos].fd = defaultFd;
                break;
            }
        }
    }

    void printFd()
    {
        for(int i=0; i<_fds_pos; i++) {
            if(_fds_array[i].fd == defaultFd) continue;
            std::cout << _fds_array[i].fd << " ";
        }
        std::cout << std::endl;
    }


private:
    std::unique_ptr<Socket> _listensock;
    bool _isRunning;

    //int _fds_array[Size]; // 辅助数组，用于将历史上所有的fd保存起来，方便每一次让select进行等待
    struct pollfd *_fds_array;
    int _fds_pos; //当前有多少个fd， 并指向下一个空位置
    int _capacity;
};